package com.hao.proxy.core;

import java.util.concurrent.BlockingQueue;

import org.jsoup.Connection;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hao.proxy.config.ProxyConfig;
import com.hao.proxy.context.Constants;
import com.hao.proxy.enums.ProxyStatusEnum;
import com.hao.proxy.http.HttpRequest;
import com.hao.proxy.model.Proxy;
import com.hao.proxy.utils.Sleep;


public class ProxyFilter implements Runnable{

	private final static Logger logger = LoggerFactory.getLogger(ProxyFilter.class);
	
	
	private BlockingQueue<Proxy> queue;
	
	private long sleep;
	
	private FilterRule filterRule;
	
	private long lastExecuteTime = System.currentTimeMillis();
	
	private boolean isRunning = false;
	
	private Connection connection;
	
	public static ProxyConfig proxyConfig;
	
	public static void startFilter(ProxyConfig proxyConfig){
		ProxyFilter.proxyConfig = proxyConfig;
		for (int i = 0; i < proxyConfig.getFilterNum(); i++) {
			ProxyFilter p = new ProxyFilter(Constants.FILTER_QUEUE,proxyConfig.getUnVerifiedProxyValidateTime(), proxyConfig.getFilterRule());
			Constants.THREAD_POOL.execute(p);
		}
		ProxyFilter p = new ProxyFilter(Constants.PROXY_QUEUE,proxyConfig.getVerifiedProxyValidateTime(), proxyConfig.getFilterRule());
		Constants.THREAD_POOL.execute(p);
		
	}
	
	public ProxyFilter(BlockingQueue<Proxy> queue, long sleep, FilterRule filterRule) {
		super();
		this.queue = queue;
		this.sleep = sleep;
		this.filterRule = filterRule;
		HttpRequest request = filterRule.getFilterRequest();
		connection = Jsoup.connect(request.getUrl())
				.requestBody(request.getPostBody())
				.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36")
				.timeout(2000)
				.headers(request.getHeaderMap())
				.method(request.getMethod())
				.ignoreContentType(true)
				.ignoreHttpErrors(true);
	}



	@Override
	public void run() {
		int count = 0;
		long sleepTime = 1000;
		while(true){
			Proxy proxy = null;
			try {
				if(queue != Constants.PROXY_QUEUE && Constants.PROXY_QUEUE.remainingCapacity()<=0){
					Sleep.sleep(60000);
					continue;
				}
				
				proxy = queue.take();
				if(count<=0){
					count = queue.size();
					sleepTime = (long) ((1D/queue.size())*sleep);
					sleepTime = sleepTime<1000?1000:sleepTime;
					sleepTime = sleepTime>sleep?sleep:sleepTime;
				}
				count--;
				logger.debug(Thread.currentThread().getName()+"待过滤的代理数："+queue.size()+"，当前验证："+proxy+"，等待时间"+sleepTime);
				lastExecuteTime = System.currentTimeMillis();
				Response response = connection.proxy(proxy.getHost(), proxy.getPort()).execute();
				if(response.statusCode()==200){
					String body = response.body();
					if(filterRule.filter(body)){
						if(!Constants.PROXY_QUEUE.contains(proxy)){
							Constants.PROXY_QUEUE.offer(proxy);
							if(ProxyStatusEnum.USING!=proxy.getStatus() && !Constants.ABLE_USE_PROXY_QUEUE.contains(proxy)){
								proxy.setStatus(ProxyStatusEnum.ABLE_USED);
								Constants.ABLE_USE_PROXY_QUEUE.offer(proxy);
							}
							logger.debug("当前可用代理数："+Constants.ABLE_USE_PROXY_QUEUE.size());
							logger.debug("当前有效代理数："+Constants.PROXY_QUEUE.size()+Constants.PROXY_QUEUE.toString());
							continue;
						}
					}
				}
				disableProxy(proxy);
			}catch (Throwable e) {
//				logger.debug("验证异常");
				disableProxy(proxy);
			}finally{
				Sleep.sleep(sleepTime);
			}
		}
	}
	
	private void disableProxy(Proxy proxy){
		proxy.setStatus(ProxyStatusEnum.ERROR);
		if(Constants.ABLE_USE_PROXY_QUEUE.contains(proxy)){
			Constants.ABLE_USE_PROXY_QUEUE.remove(proxy);
		}
//		if(Context.PROXY_QUEUE.contains(proxy)){
//			Context.PROXY_QUEUE.remove(proxy);
//		}
	}
	
	public BlockingQueue<Proxy> getQueue() {
		return queue;
	}

	
	public void setQueue(BlockingQueue<Proxy> queue) {
		this.queue = queue;
	}

	
	public long getSleep() {
		return sleep;
	}

	
	public void setSleep(long sleep) {
		this.sleep = sleep;
	}

	
	public FilterRule getFilterRule() {
		return filterRule;
	}

	
	public void setFilterRule(FilterRule filterRule) {
		this.filterRule = filterRule;
	}

	
	public long getLastExecuteTime() {
		return lastExecuteTime;
	}

	
	public void setLastExecuteTime(long lastExecuteTime) {
		this.lastExecuteTime = lastExecuteTime;
	}

	
	public boolean isRunning() {
		return isRunning;
	}

	
	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}

}
